
package Zim::Components::Calendar;

use strict;
use vars '$AUTOLOAD';
use POSIX qw(strftime);
use Gtk2::Gdk::Keysyms;

our $VERSION = '0.14';

=head1 NAME

Zim::Components::Calendar - Calendar widget for zim

=head1 DESCRIPTION

FIXME descriptve text

=head1 METHODS

=over 4

=item C<new(app => PARENT)>

Simple constructor.

=item C<init()>

Method called by the constructor.

=cut

# TODO Fix extra icon(s)
# TODO make repository use different template for date_namespace
# TODO make the pathbar ignore :Date:

my @ui_toggle_actions = (
	# name,       stock id,     label,        accelerator,      tooltip
	['TCalendar', 'gtk-paste',  'Calen_dar',   '<ctrl><shift>D', 'Show calendar', \&on_TCalendar, 0],
);
my @ui_actions = (
	['Today',     undef,        'To_day',      '<alt>D',         'Today',         \&on_Today ],
);

my $ui_layout = q{<ui>
	<menubar name='MenuBar'>
		<menu action='ViewMenu'>
			<placeholder name='PluginItems'>
				<menuitem action='TCalendar'/>
			</placeholder>
		</menu>
		<menu action='GoMenu'>
			<placeholder name='PluginItems'>
				<menuitem action='Today'/>
			</placeholder>
		</menu>
	</menubar>
	<toolbar name='ToolBar'>
		<toolitem action='TCalendar'/>
	</toolbar>
</ui>};

my ($k_return, $k_kp_enter, $k_space, $k_escape)
	= @Gtk2::Gdk::Keysyms{qw/Return KP_Enter space Escape/};

sub new {
	my $class = shift;
	my $self = bless {@_}, $class;
	$self->init();
	return $self;
}

sub init {
	my $self = shift;
	my $app = $self->{app};

	$app->{settings}{cal_namespace} = 
		$app->{repository}->resolve_page(
			$app->{settings}{cal_namespace} )->name;
	$app->{settings}{cal_namespace} =~ s/\:?$/:/;

#	Gtk2::Stock->add(
#		{stock_id => 'calendar',       label => 'Calendar'},
#		{stock_id => 'calendar-today', label => 'Today'   }, );
#	my $factory = Gtk2::IconFactory->new;
#	$factory->add_default;
#	my $pixbuf = Gtk2::Gdk::Pixbuf->new_from_file(
#		'/usr/share/icons/hicolor/24x24/stock/generic/stock_calendar.png' );
#	my $icon_set = Gtk2::IconSet->new_from_pixbuf($pixbuf);
#	$factory->add ("calendar", $icon_set);
#	$pixbuf = Gtk2::Gdk::Pixbuf->new_from_file(
#		'/usr/share/icons/hicolor/24x24/stock/generic/stock_calendar-view-month.png' );
#	$icon_set = Gtk2::IconSet->new_from_pixbuf($pixbuf);
#	$factory->add ("calendar-today", $icon_set);
		
	my $actions = Gtk2::ActionGroup->new("Calendar");
	$actions->add_actions(\@ui_actions, $self);
	$actions->add_toggle_actions(\@ui_toggle_actions, $self);
	$self->{app}{ui}->insert_action_group($actions, 0);
	$self->{app}{ui}->add_ui_from_string($ui_layout);
	$self->{actions} = $actions;

	my $dialog = Gtk2::Dialog->new(
		'Calendar - Zim', $self->{app}{window},
	       	[qw/destroy-with-parent no-separator/],
	);
	$dialog->set_resizable(0);
	$dialog->signal_connect(delete_event => sub {
			$actions->get_action('TCalendar')->set_active(0);
			return 1;
		} );
	$self->{window} = $dialog;

	my $calendar = Gtk2::Calendar->new();
	$calendar->display_options (
		[qw/show-heading show-day-names show-week-numbers/] );
	$dialog->vbox->add($calendar);
	$self->{calendar} = $calendar;

	$calendar->signal_connect(key_press_event => \&on_key_press_event, $self);
	$calendar->signal_connect(button_press_event => \&on_button_press_event, $self);
	$calendar->signal_connect(day_selected => \&on_day_selected_tmp, $self);
	$calendar->signal_handlers_block_by_func(\&on_day_selected_tmp);
	$calendar->signal_connect(day_selected_double_click => \&on_day_selected, $self);
	$calendar->signal_connect(month_changed => \&on_month_changed, $app);
	
	$app->signal_connect('page_loaded' => \&on_page_loaded);
	
	$self->{app}->signal_connect(gui_show => sub {
		$actions->get_action('TCalendar')->set_active(
			$app->{settings}{show_cal} );
	} );
}

sub on_TCalendar {
	my $self = pop;
	my $vis = $self->{window}->visible;
	$vis ? $self->hide : $self->show;
}

sub on_Today {
	my $self = pop;
	my ($day, $month, $year) = ( localtime )[3, 4, 5];
	$year += 1900;
	$self->load_date($day, $month, $year);
}

sub on_key_press_event {
	my ($cal, $event, $self) = @_;
	my $val = $event->keyval;
	if ($val == $k_return or $val == $k_kp_enter) { # Enter
		# TODO trigger space keybinding on calendar widget
	}
	elsif ($val == $k_space) { # Space
		$cal->signal_handlers_unblock_by_func(\&on_day_selected_tmp);
	}
	elsif ($val == $k_escape) {
		$self->{actions}->get_action('TCalendar')->set_active(0);
		return 1;
	}
	return 0; 
}

sub on_button_press_event {
	my ($cal, $event, $self) = @_;
	return unless $event->type eq 'button-press';
	$cal->signal_handlers_unblock_by_func(\&on_day_selected_tmp)
		if $event->button == 1;
	return 0;
}

sub on_day_selected { $_[1]->load_date( reverse $_[0]->get_date ) }

sub on_day_selected_tmp {
	$_[0]->signal_handlers_block_by_func(\&on_day_selected_tmp);
	goto &on_day_selected;
}

sub on_month_changed {
	my ($cal, $app) = @_;
	$cal->clear_marks;
	
	my $nspace = $app->{settings}{cal_namespace};
	my ($year, $month, $day) = $cal->get_date;
	$year -= 1900;
	my $string = strftime('%Y_%m', 0, 0, 0, $day, $month, $year);
#	warn "Looking for $string in $nspace\n";
	for ($app->{repository}->list_pages($nspace)) {
#		warn "$_\n";
		/^$string\_(\d{2})/ or next;
		$cal->mark_day($1);
#		warn "Marked $1\n";
	}
}

sub on_page_loaded {
	my ($app, $page) = @_;
	my $cal = $app->Calendar;
	return unless $app->{settings}{show_cal};
	my $nspace = $app->{settings}{cal_namespace};
#	warn "Comparing $page wiht $nspace\n";
	$page =~ /^:*$nspace:*(\d{4})_(\d{2})_(\d{2})/ or return;
	my ($day, $month, $year) = ($3, $2, $1);
	$month -= 1; # 0 based
	$cal->select_month($month, $year);
	$cal->select_day($day);
}

sub AUTOLOAD {
	my $self = shift;
	$AUTOLOAD =~ s/^.*:://;
	return if $AUTOLOAD eq 'DESTROY';
	return $self->{calendar}->$AUTOLOAD(@_);
}

=item C<load_date(DAY, MONTH, YEAR)>

Load the zim page coresponding to this date.

=cut

sub load_date {
	my ($self, $day, $month, $year) = @_;
	#warn "User selected: $day, $month, $year\n";
	$year -= 1900;
	my $name = strftime('%Y_%m_%d', 0, 0, 0, $day, $month, $year);
	$name = $self->{app}{settings}{cal_namespace}.$name;
	my $page = $self->{app}{repository}->resolve_page($name);
	#warn "Got ".$page->name." for $name\n";
	$self->{app}->load_page($page);
}

=item C<show()>

Show this component.

=cut

sub show {
	my $self = shift;
	my $w = $self->{window};
	$w->set_no_show_all(0);
	$w->move( @{$self->{position}} ) if $self->{position};
	$w->show_all;
	$w->move( @{$self->{position}} ) if $self->{position};
	$self->{app}{settings}{show_cal} = 1;
	&on_page_loaded($self->{app}, $self->{app}{page}->name);
}

=item C<hide()>

Hide this component.

=cut

sub hide {
	my $self = shift;
	my $w = $self->{window};
	$self->{position} = [ $w->get_position ];
	$w->hide_all;
	$w->set_no_show_all(1);
	$self->{app}{settings}{show_cal} = 0;
}

1;

__END__

=back

=head1 AUTHOR

Jaap Karssenberg (Pardus) E<lt>pardus@cpan.orgE<gt>

Copyright (c) 2006 Jaap G Karssenberg. All rights reserved.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.

=head1 SEE ALSO

=cut

